use super::BackupResult;
use super::BackupStatistics;
use super::matching::MatchProduct;
use crate::recipe::ChunkPointer;
use crate::recipe::FileInfo;
use crate::chunk::Chunk;

use parking_lot::Mutex;
use pipelines::{Sender,Receiver};

use std::fmt::Debug;
use std::sync::Arc;
use std::time::Instant;

pub struct DeltaEncoder {
    statistics:Arc<Mutex<BackupStatistics>>,
}

impl DeltaEncoder {
    pub fn new(statictics:Arc<Mutex<BackupStatistics>>) -> Self {
        Self {
            statistics:statictics,
        }
    }

    pub fn encode<P:ChunkPointer+Debug+Send>(&self,out:&Sender<EncoderProduct<P>>,recv:Receiver<MatchProduct<P>>) -> BackupResult<()> {
        let mut cost_time:u128 = 0;
        for product in recv {
            match product {
                MatchProduct::FileInfo(info) => {
                    out.send(EncoderProduct::FileInfo(info));
                }
                MatchProduct::ChunkPointer(chunk_pointer) => {
                    out.send(EncoderProduct::ChunkPointer(chunk_pointer));
                },
                MatchProduct::Chunk(chunk) => {
                    let now = Instant::now();
                    chunk.delta();
                    cost_time += now.elapsed().as_micros();
                    out.send(EncoderProduct::Chunk(chunk));
                },
            }
        }
        self.statistics.lock().set_delta_phase_time(cost_time);
        Ok(())
    }
}

pub enum EncoderProduct<P:ChunkPointer+Send> {
	FileInfo(FileInfo),
	ChunkPointer(Box<P>),
	Chunk(Arc<Chunk>),
}
